home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / lib / libpq / pqcomm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-02  |  17.7 KB  |  816 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    pqcomm.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    Communication functions between the Frontend and the Backend
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *    pq_gettty     - return the name of the tty in the given buffer
  10.  *    pq_getport     - return the PGPORT setting or 4321 if not set
  11.  *    pq_close     - close input / output connections
  12.  *    pq_flush     - flush pending output
  13.  *    pq_getstr     - get a null terminated string from connection
  14.  *    pq_getnchar     - get n characters from connection
  15.  *    pq_getint     - get an integer from connection
  16.  *    pq_putstr     - send a null terminated string to connection
  17.  *    pq_putnchar     - send n characters to connection
  18.  *    pq_putint     - send an integer to connection
  19.  *    pq_getinaddr     - initialize address from host and port number
  20.  *    pq_getinserv     - initialize address from host and service name
  21.  *    pq_connect     - create remote input / output connection
  22.  *    pq_accept     - accept remote input / output connection
  23.  *      pq_async_notify - receive notification from backend.
  24.  *
  25.  *   NOTES
  26.  *     These functions are used by both frontend applications and
  27.  *    the postgres backend.
  28.  *
  29.  *   IDENTIFICATION
  30.  *    $Header: /private/postgres/src/lib/libpq/RCS/pqcomm.c,v 1.18 1992/04/21 13:13:53 clarsen Exp $
  31.  * ----------------------------------------------------------------
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <sys/types.h>
  36. #include <sys/socket.h>
  37. #include <fcntl.h>
  38. #include <netdb.h>
  39. #include <netinet/in.h>
  40. #include <signal.h>
  41.  
  42. #include "tmp/pqcomm.h"
  43. #include "tmp/c.h"
  44. #include "utils/log.h"
  45.  
  46. RcsId ("$Header: /private/postgres/src/lib/libpq/RCS/pqcomm.c,v 1.18 1992/04/21 13:13:53 clarsen Exp $");
  47.  
  48. /* ----------------
  49.  *    declarations
  50.  * ----------------
  51.  */
  52. extern char **environ;
  53. char **ep;
  54. char *dp;
  55.  
  56. FILE *Pfout, *Pfin;
  57. int PQAsyncNotifyWaiting;    /* for async. notification */
  58. extern char PQerrormsg[];
  59.  
  60. char *strcpy(), *ttyname();
  61.  
  62. /* forward declarations */
  63. void pq_regoob ARGS((void (*fptr )()));
  64. void pq_unregoob ARGS((void ));
  65. void pq_async_notify ARGS((void ));
  66.  
  67.  
  68. /* --------------------------------
  69.  *    pq_init - open portal file descriptors
  70.  * --------------------------------
  71.  */
  72. void
  73. pq_init(fd)
  74.     int fd;
  75. {
  76.     Pfin = fdopen(fd, "r");
  77.     Pfout = fdopen(dup(fd), "w");
  78.     if (!Pfin || !Pfout)
  79.     elog(FATAL, "Couldn't initialize socket connection");
  80.     PQnotifies_init();
  81. }
  82.  
  83. /* --------------------------------
  84.  *    pq_gettty - return the name of the tty in the given buffer
  85.  * --------------------------------
  86.  */
  87. void
  88. pq_gettty(tp)
  89.     char tp[20];
  90. {    
  91.     strcpy(tp, ttyname(0));
  92. }
  93.  
  94. /* --------------------------------
  95.  *    pq_getport - return the PGPORT setting or 4321 if not set
  96.  * --------------------------------
  97.  */
  98. int
  99. pq_getport()
  100. {
  101.     char *env, *getenv();
  102.     int  port_no;
  103.     
  104.     env = getenv("PGPORT");
  105.     
  106.     if (env) {
  107.     port_no = atoi(env);
  108.     } else
  109.     port_no = 4321;
  110.     
  111.     return
  112.     port_no;
  113. }
  114.  
  115. /* --------------------------------
  116.  *    pq_close - close input / output connections
  117.  * --------------------------------
  118.  */
  119. void
  120. pq_close()
  121. {
  122.     if (Pfin) {
  123.     fclose(Pfin);
  124.     Pfin = NULL;
  125.     }
  126.     if (Pfout) {
  127.     fclose(Pfout);
  128.     Pfout = NULL;
  129.     }
  130.     PQAsyncNotifyWaiting = 0;
  131.     PQnotifies_init();
  132.     pq_unregoob();
  133. }
  134.  
  135. /* --------------------------------
  136.  *    pq_flush - flush pending output
  137.  * --------------------------------
  138.  */
  139. void
  140. pq_flush()
  141. {
  142.     if (Pfout)
  143.     fflush(Pfout);
  144. }
  145.  
  146. /* --------------------------------
  147.  *    pq_getstr - get a null terminateed string from connection
  148.  * --------------------------------
  149.  */
  150. int
  151. pq_getstr(s, maxlen)
  152.     char *s;
  153.     int     maxlen;
  154. {
  155.     int    c;
  156.     
  157.     if (Pfin == (FILE *) NULL)
  158.     {
  159.     elog(DEBUG, "Input descriptor is null");
  160.     return (EOF);
  161.     }
  162.  
  163.     while (maxlen-- && (c = getc(Pfin)) != EOF && c)
  164.     *s++ = c;
  165.     *s = '\0';
  166.  
  167.     /* -----------------
  168.      *     If EOF reached let caller know
  169.      * -----------------
  170.      */
  171.     if (c == EOF)
  172.     return EOF;
  173.     else
  174.     return !EOF;
  175. }
  176.  
  177. /*
  178.  * USER FUNCTION - gets a newline-terminated string from the backend.
  179.  * 
  180.  * Chiefly here so that applications can use "COPY <rel> () from stdin"
  181.  * and read the output string.  Returns a null-terminated string in s and
  182.  * EOF if it is detected.
  183.  */
  184.  
  185. int
  186. PQgetline(s, maxlen)
  187.  
  188. char *s;
  189. int maxlen;
  190.  
  191. {
  192.     int c;
  193.  
  194.     if (Pfin == (FILE *) NULL)
  195.     return (EOF);
  196.  
  197.     while (maxlen-- && (c = getc(Pfin)) != '\n' && c != EOF)
  198.     {
  199.         *s++ = c;
  200.     }
  201.     *s = '\0';
  202.  
  203.     /* -----------------
  204.      *     If EOF reached let caller know
  205.      * -----------------
  206.      */
  207.     if (c == EOF)
  208.     return EOF;
  209.     else
  210.     return !EOF;
  211. }
  212.  
  213. /*
  214.  * USER FUNCTION - sends a string to the backend.
  215.  * 
  216.  * Chiefly here so that applications can use "COPY <rel> () to stdout"
  217.  * and read the output string.  Returns a null-terminated string in s and
  218.  * EOF if it is detected.
  219.  */
  220.  
  221. int
  222. PQputline(s)
  223.  
  224. char *s;
  225.  
  226. {
  227.     if (Pfout) {
  228.     (void) fputs(s, Pfout);
  229.     fflush(Pfout);
  230.     }
  231. }
  232.  
  233. /* --------------------------------
  234.  *    pq_getnchar - get n characters from connection
  235.  * --------------------------------
  236.  */
  237. int
  238. pq_getnchar(s, off, maxlen)
  239.     char *s;
  240.     int     off, maxlen;
  241. {
  242.     int    c;
  243.     
  244.     if (Pfin == (FILE *) NULL)
  245.     {
  246.     elog(DEBUG, "Input descriptor is null");
  247.     return (EOF);
  248.     }
  249.  
  250.     s += off;
  251.     while (maxlen-- && (c = getc(Pfin)) != EOF)
  252.     *s++ = c;
  253.  
  254.     /* -----------------
  255.      *     If EOF reached let caller know
  256.      * -----------------
  257.      */
  258.     if (c == EOF)
  259.     {
  260.     return EOF;
  261.     }
  262.     else
  263.     return !EOF;
  264. }
  265.  
  266. /* --------------------------------
  267.  *    pq_getint - get an integer from connection
  268.  * --------------------------------
  269.  */
  270. int
  271. pq_getint(b)
  272.     int    b;
  273. {
  274.     int    n, c, p;
  275.     
  276.     if (Pfin == (FILE *) NULL)
  277.     {
  278.     elog(DEBUG, "Input descriptor is null");
  279.     return (EOF);
  280.     }
  281.  
  282.     n = p = 0;
  283.     while (b-- && (c = getc(Pfin)) != EOF && p < 32) {
  284.     n |= (c & 0xff) << p;
  285.     p += 8;
  286.     }
  287.  
  288.     return n;
  289. }
  290.  
  291. /* --------------------------------
  292.  *    pq_putstr - send a null terminated string to connection
  293.  * --------------------------------
  294.  */
  295. void
  296. pq_putstr(s)
  297.     char *s;
  298. {
  299.     int status;
  300.  
  301.     if (Pfout) {
  302.     status = fputs(s, Pfout);
  303.     if (status == EOF)
  304.     {
  305.         strcpy(PQerrormsg,"pq_putstr: write to backend failed\n");
  306.         fprintf(stderr, PQerrormsg);
  307.     }
  308.     status = fputc('\0', Pfout);
  309.     if (status == EOF)
  310.     {
  311.         strcpy(PQerrormsg, "pq_putstr: write to backend failed\n");
  312.         fprintf(stderr, PQerrormsg);
  313.     }
  314.     }
  315. }
  316.  
  317. /* --------------------------------
  318.  *    pq_putnchar - send n characters to connection
  319.  * --------------------------------
  320.  */
  321. void
  322. pq_putnchar(s, n)
  323.     char *s;
  324.     int n;
  325. {
  326.     int status;
  327.  
  328.     if (Pfout) {
  329.     while (n--)
  330.     {
  331.         status = fputc(*s++, Pfout);
  332.         if (status == EOF)
  333.         {
  334.         strcpy(PQerrormsg, "pq_putnchar: write to backend failed\n");
  335.         fprintf(stderr, PQerrormsg);
  336.         }
  337.     }
  338.     }
  339. }
  340.  
  341. /* --------------------------------
  342.  *    pq_putint - send an integer to connection
  343.  * --------------------------------
  344.  */
  345. void
  346. pq_putint(i, b)
  347.     int    i, b;
  348. {
  349.     int status;
  350.  
  351.     if (b > 4)
  352.     b = 4;
  353.     
  354.     if (Pfout) {
  355.     while (b--) {
  356.         status = fputc(i & 0xff, Pfout);
  357.         i >>= 8;
  358.         if (status == EOF)
  359.         {
  360.         strcpy(PQerrormsg, "pq_putint: write to backend failed\n");
  361.         fprintf(stderr, PQerrormsg);
  362.         }
  363.     }
  364.     }
  365. }
  366.  
  367. /* ---
  368.  *     pq_sendoob - send a string over the out-of-band channel
  369.  *     pq_recvoob - receive a string over the oob channel
  370.  *  NB: Fortunately, the out-of-band channel doesn't conflict with
  371.  *      buffered I/O because it is separate from regular com. channel.
  372.  * ---
  373.  */
  374. int
  375. pq_sendoob(msg,len)
  376.      char *msg;
  377.      int len;
  378. {
  379.     int fd = fileno(Pfout);
  380.     return send(fd,msg,len,MSG_OOB);
  381. }
  382.  
  383. int
  384. pq_recvoob(msgPtr,lenPtr)
  385.      char *msgPtr;
  386.      int *lenPtr;
  387. {
  388.     int fd = fileno(Pfout);
  389.     int len = 0, n;
  390.     len = recv(fd,msgPtr+len,*lenPtr,MSG_OOB);
  391.     *lenPtr = len;
  392.     return len;
  393. }
  394.  
  395. /* --------------------------------
  396.  *    pq_getinaddr - initialize address from host and port number
  397.  * --------------------------------
  398.  */
  399. int
  400. pq_getinaddr(sin, host, port)
  401.     struct    sockaddr_in *sin;
  402.     char    *host;
  403.     int        port;
  404. {
  405.     struct    hostent    *hs;
  406.     
  407.     bzero((char *)sin, sizeof *sin);
  408.     
  409.     if (host) {
  410.     if (*host >= '0' && *host <= '9')
  411.         sin->sin_addr.s_addr = inet_addr(host);
  412.     else {
  413.         if (!(hs = gethostbyname(host))) {
  414.         perror(host);
  415.         return(1);
  416.         }
  417.         if (hs->h_addrtype != AF_INET) {
  418.         sprintf(PQerrormsg,"%s: Not Internet\n",host);
  419.         fprintf(stderr,PQerrormsg);
  420.         return(1);
  421.         }
  422.         bcopy(hs->h_addr, (char *)&sin->sin_addr, hs->h_length);
  423.     }
  424.     }
  425.     
  426.     sin->sin_family = AF_INET;
  427.     sin->sin_port = htons(port);
  428.     
  429.     return(0);
  430. }
  431.  
  432. /* --------------------------------
  433.  *    pq_getinserv - initialize address from host and servive name
  434.  * --------------------------------
  435.  */
  436. int
  437. pq_getinserv(sin, host, serv)
  438.     struct    sockaddr_in *sin;
  439.     char    *host, *serv;
  440. {
  441.     struct    servent    *ss;
  442.     
  443.     if (*serv >= '0' && *serv <= '9')
  444.     return
  445.         pq_getinaddr(sin, host, atoi(serv));
  446.     
  447.     if (!(ss = getservbyname(serv, NULL))) {
  448.     fputs(serv, stderr);
  449.     fputs(": Unknown service\n", stderr);
  450.     sprintf(PQerrormsg,"%s: Unknown service\n",serv);
  451.     return(1);
  452.     }
  453.     
  454.     return
  455.     pq_getinaddr(sin, host, ntohs(ss->s_port));
  456. }
  457.  
  458. /* ----------------------------------------
  459.  * pq_connect  -- initiate a communication link between client and
  460.  *    POSTGRES backend via postmaster.
  461.  *
  462.  * RETURNS: STATUS_ERROR, if arguments are wrong or local communication
  463.  *    status is screwed up (can't create socket, etc).  STATUS_OK
  464.  *    otherwise.
  465.  *
  466.  * SIDE_EFFECTS: initiates connection.  
  467.  *               SIGURG handler is set (async notification)
  468.  *
  469.  * NOTE: we don't wait for any error messages from the backend/postmaster.
  470.  *    That means that if the fork fails or the startup message is corrupted,
  471.  *    we won't find out until the first Send/Receive message cal.
  472.  * ----------------------------------------
  473.  */
  474. int
  475. pq_connect(dbname,user,args,hostName,debugTty,execFile,portName)
  476. char    *dbname;
  477. char    *user;
  478. char    *args;
  479. char    *hostName;
  480. char    *debugTty;
  481. char    *execFile;
  482. short    portName;
  483. {
  484. /*
  485.  * This data structure is used for the seq-packet protocol.  It
  486.  * describes the frontend-backend connection.
  487.  */
  488.   Connection        *MyConn = NULL;
  489.   Port            *SendPort = NULL; /* This is a TCP or UDP socket */
  490.   StartupPacket        startup;
  491.   int            sock;
  492.   Addr            addr;
  493.   int            status;
  494.  
  495.   /*
  496.    * Initialize the startup packet.  Packet fields defined in comm.h
  497.    */
  498.   strncpy(startup.database,dbname,sizeof(startup.database));
  499.   strncpy(startup.user,user,sizeof(startup.user));
  500.   strncpy(startup.options,args,sizeof(startup.options));
  501.   strncpy(startup.tty,debugTty,sizeof(startup.tty));
  502.   if (execFile != NULL)
  503.   {
  504.     strncpy(startup.execFile, execFile, sizeof(startup.execFile));
  505.   }
  506.   else
  507.   {
  508.     strncpy(startup.execFile, "", sizeof(startup.execFile));
  509.   }
  510.  
  511.   /* If no port  was suggested grab the default or PGPORT value */
  512.   if (!portName)
  513.     portName = pq_getport();
  514.   /*
  515.    * initialize connection structure.  This is really needed
  516.    * only for the sequenced packet protocol, but these initializations
  517.    * are important to the packet.c library.
  518.    */
  519.   MyConn = (Connection *) malloc(sizeof(Connection));
  520.   bzero(MyConn, sizeof(Connection));
  521.   MyConn->id = INVALID_ID;
  522.   MyConn->seqno = INITIAL_SEQNO;
  523.  
  524.   /*
  525.    * Open a connection to postmaster/backend.
  526.    */
  527.   status = StreamOpen(hostName,portName,&sock);
  528.   if (status != STATUS_OK)
  529.     return(STATUS_ERROR);
  530.  
  531.   /*
  532.    * Save communication port state.
  533.    */
  534.   SendPort = (Port *) malloc(sizeof(Port));
  535.   bzero(SendPort, sizeof(Port));
  536.   SendPort->sock =  sock;
  537.   /*
  538.    * kai: Linux TCP/IP wants sock.addr filled by the receiver
  539.    */
  540. #ifdef linux
  541.   {
  542.     struct hostent *hp;
  543.  
  544.     /* The gethostbyname() just succeeded for the StreamOpen() call, so
  545.        it shouldn't fail, but who knows. */
  546.     if (! hostName)
  547.       hostName = "localhost";
  548.     if ((hp = gethostbyname(hostName)) && hp->h_addrtype == AF_INET)
  549.       bcopy(hp->h_addr, (char *)&(SendPort -> addr.sin_addr), hp->h_length);
  550.     else {
  551.       fprintf(stderr, 
  552.       "StreamServerPort: cannot find hostname '%s' for stream port\n", 
  553.       hostName);
  554.       return(STATUS_ERROR);
  555.     }
  556.     SendPort -> addr.sin_family = AF_INET;
  557.     SendPort -> addr.sin_port = htons(portName);
  558.   }
  559. #endif
  560.  
  561.   /* initialize */
  562.   status = PacketSend(SendPort, MyConn, 
  563.               &startup, STARTUP_MSG, sizeof(startup), BLOCKING);
  564.  
  565.   /* set up streams over which communic. will flow */
  566.   Pfout = fdopen(sock, "w");
  567.   Pfin = fdopen(dup(sock), "r");
  568.   if (!Pfout && !Pfin)
  569.   {
  570.       strcpy(PQerrormsg, "Couldn't fdopen the socket descriptor\n");
  571.     fprintf(stderr,PQerrormsg);
  572.     return(STATUS_ERROR);
  573.   }
  574.   
  575.   PQAsyncNotifyWaiting = 0;
  576.   PQnotifies_init();
  577.   pq_regoob(pq_async_notify);
  578.  
  579.   if (status != STATUS_OK)
  580.     return(STATUS_ERROR);
  581.  
  582.   return(STATUS_OK);
  583. }
  584.  
  585. /* --------------------------------
  586.  *    pq_accept - accept remote input / output connection
  587.  * --------------------------------
  588.  */
  589. int
  590. pq_accept()
  591. {
  592.     struct sockaddr_in    sin;
  593.     int            fd, nfd, i;
  594.     
  595.     if (!(fd = socket(AF_INET, SOCK_STREAM, 0)))
  596.     return(-2);
  597.     
  598.     pq_getinaddr(&sin, 0, pq_getport());
  599.     if (bind(fd, &sin, sizeof sin))
  600.     return(-3);
  601.  
  602. /* kai: the man-page of listen() tells, that there is a maximum of 5
  603.         unprocessed connects, so I assume SOMAXCONN = 5 */
  604. #if defined(linux) && ! defined(SOMAXCONN)
  605. #define SOMAXCONN 5
  606. #endif
  607.     listen(fd, SOMAXCONN);
  608.     if ((nfd = accept(fd, NULL, NULL)) < 0)
  609.     return(-1);
  610.     
  611.     close(fd);
  612.     Pfout = fdopen(nfd, "w");
  613.     Pfin = fdopen(dup(nfd), "r");
  614.     
  615.     return(0);
  616. }
  617.  
  618. /*
  619.  * register an out-of-band listener proc--at most one allowed.
  620.  * This is used for receiving async. notification from the backend.
  621.  */
  622. void 
  623. pq_regoob(fptr)
  624.      void (*fptr)();
  625. {
  626.     int fd = fileno(Pfout);
  627.     fcntl(fd,F_SETOWN,getpid());
  628.     (void) signal(SIGURG,fptr);
  629. }
  630.  
  631. void pq_unregoob()
  632. {
  633.     signal(SIGURG,SIG_DFL);
  634. }
  635.  
  636.  
  637. void pq_async_notify() {
  638.     char msg[20];
  639.     int len = sizeof(msg);
  640.     if (pq_recvoob(msg,&len) >= 0) {
  641.     /* debugging */
  642.     printf("received notification: %s\n",msg);
  643.     PQAsyncNotifyWaiting = 1;
  644. /*    PQappendNotify(msg+1);*/
  645.     } else {
  646.     extern int errno;
  647.     printf("SIGURG but no data: len = %d, err=%d\n",len,errno);
  648.     }
  649. }
  650.  
  651. /*
  652.  * Streams -- wrapper around Unix socket system calls
  653.  *
  654.  *
  655.  *    Stream functions are used for vanilla TCP connection protocol.
  656.  */
  657.  
  658. /*
  659.  * StreamServerPort -- open a sock stream "listening" port.
  660.  *
  661.  * This initializes the Postmaster's connection
  662.  *    accepting port.  
  663.  *
  664.  * ASSUME: that this doesn't need to be non-blocking because
  665.  *    the Postmaster uses select() to tell when the socket
  666.  *    is ready.
  667.  *
  668.  * RETURNS: STATUS_OK or STATUS_ERROR
  669.  */
  670. StreamServerPort(hostName,portName,fdP)
  671. char    *hostName;
  672. short    portName;
  673. int    *fdP;
  674. {
  675.   struct sockaddr_in    sin;
  676.   int            fd;
  677.   struct hostent    *hp;
  678.  
  679.   if (! hostName)
  680.     hostName = "localhost";
  681.  
  682.   bzero((char *)&sin, sizeof sin);
  683.  
  684. #ifdef NOTDEF
  685.   if ((hp = gethostbyname(hostName)) && hp->h_addrtype == AF_INET)
  686.     bcopy(hp->h_addr, (char *)&(sin.sin_addr), hp->h_length);
  687.   else {
  688.     fprintf(stderr, 
  689.         "StreamServerPort: cannot find hostname '%s' for stream port\n", 
  690.         hostName);
  691.     return(STATUS_ERROR);
  692.   }
  693. #endif
  694.  
  695.   if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  696.       strcpy(PQerrormsg,"StreamServerPort: cannot make socket descriptor for port\n");
  697.     fprintf(stderr,PQerrormsg);
  698.     return(STATUS_ERROR);
  699.   }
  700.  
  701.   sin.sin_family = AF_INET;
  702.   sin.sin_port = htons(portName);
  703.  
  704.   if (bind(fd, (char *)&sin, sizeof sin) < 0) {
  705.     strcpy(PQerrormsg,"StreamServerPort: cannot bind to port\n");
  706.     fprintf(stderr,PQerrormsg);
  707.     return(STATUS_ERROR);
  708.   }
  709.  
  710.   listen(fd, SOMAXCONN);
  711.  
  712.   /* MS: I took this code from Dillon's version.  It makes the 
  713.    * listening port non-blocking.  That is not necessary (and
  714.    * may tickle kernel bugs).
  715.  
  716.    (void) fcntl(fd, F_SETFD, 1);
  717.    (void) fcntl(fd, F_SETFL, FNDELAY);
  718.    */
  719.  
  720.   *fdP = fd;
  721.   return(STATUS_OK);
  722. }
  723.  
  724. /*
  725.  * StreamConnection -- create a new connection with client using
  726.  *    server port.
  727.  *
  728.  * This one should be non-blocking.  The client could send us
  729.  * part of a message.  Would not do at all to have the server
  730.  * block waiting for the message to complete.  Not neccesary
  731.  * to return the address, but it could conceivably be used
  732.  * for protection checking.
  733.  * 
  734.  * RETURNS: STATUS_OK or STATUS_ERROR
  735.  */
  736. StreamConnection(server_fd,new_fdP,addrP)
  737. int             server_fd;
  738. int            *new_fdP;
  739. struct sockaddr_in    *addrP;
  740. {
  741.   long             len = sizeof (struct sockaddr_in);
  742.  
  743.   if ((*new_fdP = accept(server_fd, (char *)addrP, &len)) < 0) {
  744.     strcpy(PQerrormsg,"StreamConnection: accept failed\n");
  745.     fprintf(stderr,PQerrormsg);
  746.     return(STATUS_ERROR);
  747.   }
  748.   /* reset to non-blocking */
  749.   fcntl(*new_fdP, F_SETFL, 1);    
  750.  
  751.   return(STATUS_OK);
  752. }
  753.  
  754. /* 
  755.  * StreamClose -- close a client/backend connection
  756.  */
  757. StreamClose(sock)
  758. int    sock;
  759. {
  760.   close(sock); 
  761. }
  762.  
  763. /* ---------------------------
  764.  * StreamOpen -- From client, initiate a connection with the 
  765.  *    server (Postmaster).
  766.  *
  767.  * RETURNS: STATUS_OK or STATUS_ERROR
  768.  *
  769.  * NOTE: connection is NOT established just because this
  770.  *    routine exits.  Local state is ok, but we haven't
  771.  *    spoken to the postmaster yet.
  772.  *
  773.  * ASSUME that the client doesn't need the net address of the
  774.  *    server after this routine exits.
  775.  * ---------------------------
  776.  */
  777. StreamOpen(hostName,portName,sockP)
  778. char    *hostName;
  779. short    portName;
  780. int    *sockP;
  781. {
  782.   struct sockaddr_in    addr;
  783.   struct hostent    *hp;
  784.   int            sock;
  785.  
  786.   if (! hostName)
  787.     hostName = "localhost";
  788.  
  789.   bzero((char *)&addr, sizeof addr);
  790.  
  791.   if ((hp = gethostbyname(hostName)) && hp->h_addrtype == AF_INET)
  792.     bcopy(hp->h_addr, (char *)&(addr.sin_addr), hp->h_length);
  793.   else {
  794.     sprintf(PQerrormsg,
  795.     "StreamPort: cannot find hostname '%s' for stream port\n",
  796.     hostName);
  797.     fprintf(stderr,PQerrormsg);
  798.     return(STATUS_ERROR);
  799.   }
  800.  
  801.   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  802.       strcpy(PQerrormsg,"StreamPort: cannot make socket descriptor for port\n");
  803.     fprintf(stderr,PQerrormsg);
  804.     return(STATUS_ERROR);
  805.   }
  806.  
  807.   addr.sin_family = AF_INET;
  808.   addr.sin_port = htons(portName);
  809.  
  810.   *sockP = sock;
  811.   if (! connect(sock, &addr, sizeof(addr)))
  812.     return(STATUS_OK);
  813.   else
  814.     return(STATUS_ERROR);
  815. }
  816.